// $Id: element.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <xpcom/array.hpp>
#include <xpcom/ptr_array.hpp>
#include <xpcom/uuid.hpp>
#include "def.hpp"
#include "interface_def.hpp"

BOOST_AUTO_TEST_CASE_TEMPLATE(test_range_check, T, test_types)
{
    using namespace xpcom;
    typedef array<T> Array;
    typedef typename Array::value_type V;

    Array a1;

    try {
        a1.at(5);
        BOOST_CHECK(false);
    } catch (const std::exception&) {
        BOOST_CHECK(true);
    }

    try {
        a1.at(0) = V();
        BOOST_CHECK(false);
    } catch (const std::exception&) {
        BOOST_CHECK(true);
    }

    Array a2(8);

    try {
        a2.at(0);
        BOOST_CHECK(true);
    } catch (const std::exception&) {
        BOOST_CHECK(false);
    }

    try {
        a2.at(7) = V();
        BOOST_CHECK(true);
    } catch (const std::exception&) {
        BOOST_CHECK(false);
    }

    try {
        a2.at(8);
        BOOST_CHECK(false);
    } catch (const std::exception&) {
        BOOST_CHECK(true);
    }

    try {
        a2.at(80) = V();
        BOOST_CHECK(false);
    } catch (const std::exception&) {
        BOOST_CHECK(true);
    }
}

BOOST_AUTO_TEST_CASE(test_element_uint32)
{
    using namespace xpcom;
    typedef array<uint32_t> Array;

    Array a1(5);

    uint32_t n = 10;
    for (Array::iterator iter = a1.begin(); iter != a1.end(); ++iter) {
        *iter = n;
        n += 10;
    }

    n = 10;
    for (Array::size_type i = 0; i < a1.size(); ++i) {
        BOOST_CHECK(a1[i] == n);
        n += 10;
    }

    BOOST_CHECK(a1.front() == 10);
    BOOST_CHECK(a1.back() == 50);

    BOOST_CHECK(a1.at(2) == 30);

    a1.front() = 50;
    a1.back() = 10;
    a1[1] = 40;
    a1.at(3) = 20;

    n = 50;
    for (Array::size_type i = 0; i < a1.size(); ++i) {
        BOOST_CHECK(a1[i] == n);
        n -= 10;
    }
}

BOOST_AUTO_TEST_CASE(test_element_bool)
{
    using namespace xpcom;
    typedef array<bool> Array;

    Array a1(4);

    bool n = false;
    for (Array::iterator iter = a1.begin(); iter != a1.end(); ++iter) {
        *iter = n;
        n = !n;
    }

    n = false;
    for (Array::size_type i = 0; i < a1.size(); ++i) {
        BOOST_CHECK(a1[i] == n);
        n = !n;
    }

    BOOST_CHECK(a1.front() == false);
    BOOST_CHECK(a1.back() == true);
    BOOST_CHECK(a1.at(2) == false);

    a1.front() = true;
    a1.back() = false;
    a1[1] = false;
    a1.at(2) = true;

    n = true;
    for (Array::size_type i = 0; i < a1.size(); ++i) {
        BOOST_CHECK(a1[i] == n);
        n = !n;
    }
}

BOOST_AUTO_TEST_CASE(test_element_pstring)
{
    using namespace xpcom;
    typedef array<char*> Array;

    Array a1(4);
    a1[0] = "test0";
    a1[1] = "test1";
    //a1[2] = "test2";
    a1[3] = "test3";

    BOOST_CHECK(a1.front() == "test0");
    BOOST_CHECK(a1.back() == "test3");
    BOOST_CHECK(a1.at(1) == "test1");
    BOOST_CHECK(!a1[2]);

    a1.at(2) = "test2";
    BOOST_CHECK(a1[2] == "test2");

    a1.front() = "test3";
    a1.back() = "test0";
    a1.at(1) = "test2";
    a1[2] = "test1";
    BOOST_CHECK(a1.front() == "test3");
    BOOST_CHECK(a1.back() == "test0");
    BOOST_CHECK(a1.at(1) == "test2");
    BOOST_CHECK(a1[2] == "test1");
}

BOOST_AUTO_TEST_CASE(test_element_uuid)
{
    using namespace xpcom;
    typedef array<uuid> Array;

    uuid id1 = { 0x64D47515, 0xADE3, 0x45d1, { 0xAB, 0xAE, 0x3A, 0x93, 0x62, 0xC5, 0xA5, 0x51 } };
    uuid id2 = { 0x64D47516, 0xADE3, 0x45d1, { 0xAB, 0xAE, 0x3A, 0x93, 0x62, 0xC5, 0xA5, 0x51 } };
    uuid id3 = { 0x64D47517, 0xADE3, 0x45d1, { 0xAB, 0xAE, 0x3A, 0x93, 0x62, 0xC5, 0xA5, 0x51 } };
    uuid id4 = { 0x64D47518, 0xADE3, 0x45d1, { 0xAB, 0xAE, 0x3A, 0x93, 0x62, 0xC5, 0xA5, 0x51 } };

    Array a1(4);
    a1[0] = id1;
    a1[1] = id2;
    //a1[2] = id3;
    a1[3] = id4;

    BOOST_CHECK(a1.front() == id1);
    BOOST_CHECK(a1.back() == id4);
    BOOST_CHECK(a1.at(1) == id2);
    BOOST_CHECK(a1[2].is_nil());

    a1[2] = id3;
    BOOST_CHECK(a1.at(2) == id3);

    a1.front() = id4;
    a1.back() = id1;
    a1.at(1) = id3;
    a1[2] = id2;
    BOOST_CHECK(a1.front() == id4);
    BOOST_CHECK(a1.back() == id1);
    BOOST_CHECK(a1.at(1) == id3);
    BOOST_CHECK(a1[2] == id2);
}

BOOST_AUTO_TEST_CASE(test_element_ptr)
{
    using namespace xpcom;
    typedef ptr_array<IBase> Array;

    X_count_guard g;
    X_count(0);
    {
        Array a1(4);
        for (int i = 0; i < 4; ++i) {
            if (i != 2)
                a1[i].reset(X_make_instance());
        }
        a1[0]->setN(0);
        a1[1]->setN(1);
        //a1[2]->setN(2);
        a1[3]->setN(3);
        BOOST_CHECK_EQUAL(X_count(), 3);

        BOOST_CHECK(a1.front()->getN() == 0);
        BOOST_CHECK(a1.back()->getN() == 3);
        BOOST_CHECK(a1.at(1)->getN() == 1);
        BOOST_CHECK(!a1[2]);

        a1[2].reset(X_make_instance());
        a1.at(2)->setN(2);
        BOOST_CHECK(a1[2]->getN() == 2);

        BOOST_CHECK_EQUAL(X_count(), 4);

        a1.front()->setN(3);
        a1.back()->setN(0);
        a1.at(1)->setN(2);
        a1[2]->setN(1);
        BOOST_CHECK(a1.front()->getN() == 3);
        BOOST_CHECK(a1.back()->getN() == 0);
        BOOST_CHECK(a1.at(1)->getN() == 2);
        BOOST_CHECK(a1[2]->getN() == 1);

        BOOST_CHECK_EQUAL(X_count(), 4);
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}
